#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>

#include "log.hpp"
#include "threadpool.hpp"
#include "Daemon.hpp"

extern Log lg;
using namespace std;

const string defaultip = "0.0.0.0";
const uint16_t defaultport = 8080;
const int backlog = 5; // 后面会详细讲

class tcp_server;//声明一下这个类

struct ThreadDate
{
public:
    ThreadDate(int sockfd, const string &clientip, const uint16_t clientport, tcp_server* ts)
    :sockfd(sockfd),
    ip(clientip),
    port(clientport),
    ts(ts)
    {}
public:
    int sockfd;
    string ip;
    uint16_t port;
    tcp_server* ts;
};

class tcp_server
{
public:
    tcp_server(const uint16_t port = defaultport, const string &ip = defaultip)
        : _listensockfd(0),
          _ip(ip),
          _port(port)
    {
    }

    void Init()
    {
        // 1、创建socket
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd < 0)
        {
            lg(Fatal, "socket create failed, errno: %d, strerror %s", errno, strerror(errno));
            exit(1);
        }
        lg(Info, "socket create success, sockfd: %d", _listensockfd);

        int opt = 1;
        setsockopt(_listensockfd, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt));//防止服务器无法立即重启


        // 2、bind
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        inet_aton(_ip.c_str(), &local.sin_addr);

        if (bind(_listensockfd, (const sockaddr *)&local, sizeof(local)) < 0)
        {
            lg(Fatal, "bind failed, errno: %d, strerror %s", errno, strerror(errno));
            exit(2);
        }
        lg(Info, "bind success, sockfd: %d", _listensockfd);

        // 3、listen
        // Tcp是面向连接的，服务器一般是比较“被动的”，服务器一直处于一种，一直在等待连接到来的状态
        if (listen(_listensockfd, backlog) < 0)
        {
            lg(Fatal, "listen failed, errno: %d, strerror %s", errno, strerror(errno));
            exit(3);
        }
        lg(Info, "listen success, sockfd: %d", _listensockfd);
    }

    //如果不是static，第一个参数是this指针
    // static void* routine(void* args)
    // {
    //     pthread_detach(pthread_self());
    //     ThreadDate* td = static_cast<ThreadDate*>(args);
    //     td->ts->Service(td->sockfd, td->ip, td->port);
        
    //     close(td->sockfd);

    //     delete(td);
    //     return nullptr;
    // }

    void Start()
    {
        //daemon(1, 0);//系统调用
        Daemon();//自己写的
        lg(Info, "tcp server is running...");
        threadpool<Task> tp;
        tp.Start();

        while (true)
        {    
            // accept
            struct sockaddr_in client;
            memset(&client, 0, sizeof(client));
            socklen_t len = sizeof(client);
            int sockfd = accept(_listensockfd, (sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                lg(Warning, "accept failed, errno: %d, strerror %s", errno, strerror(errno));
                continue;
            }

            uint16_t c_port = ntohs(client.sin_port);
            string c_ip = inet_ntoa(client.sin_addr);
            lg(Info, "get new client request [%s:%d], sockfd : %d", c_ip.c_str(), c_port, sockfd);

            // 1、单进程版——如果一个客户端正在访问，那么只有当这个客户端结束后，另一个客户端才可以访问
            //  Service(sockfd, c_ip, c_port);
            //  close(sockfd);

            // 2、多进程版
            // pid_t pid = fork();
            // if (pid == 0)
            // {
            //     // child
            //     close(_listensockfd);
            //     if(fork() > 0) exit(0);//子进程退出，为了让外面的父进程回收
            //     //孙子进程做的处理，此时孙子进程成为了孤儿进程，由bash领养
            //     Service(sockfd, c_ip, c_port);
            //     close(sockfd);
            //     exit(0);
            // }

            // // father
            // close(sockfd);
            // pid_t wpid = waitpid(pid, nullptr, 0);//等待子进程退出

            //3、多线程版
            // pthread_t tid;
            // ThreadDate* td = new ThreadDate(sockfd, c_ip, c_port, this);
            // pthread_create(&tid, nullptr, routine, td);


            //4、线程池版
            Task task(sockfd, c_ip, c_port);
            tp.Push(task);

        }
    }

    // void Service(int sockfd, const string &clientip, const uint16_t clientport)
    // {
    //     // 接收和发送
    //     while (true)
    //     {
    //         char inbuffer[1024] = {0};
    //         ssize_t s = read(sockfd, inbuffer, sizeof(inbuffer));
    //         if (s > 0) // 读到了数据
    //         {
    //             inbuffer[s] = 0;
    //             cout << inbuffer << endl;
    //             string mess = "server echo#";
    //             mess += inbuffer;
    //             write(sockfd, mess.c_str(), mess.size());
    //         }
    //         else if (s == 0) // 客户端退出
    //         {
    //             lg(Info, "[%s:%d] quit, server close sockfd: %d", clientip.c_str(), clientport, sockfd);
    //             break;
    //         }
    //         else // read出错
    //         {
    //             lg(Warning, "read error, sockfd: %d, client ip: %s, client port: %d", sockfd, clientip.c_str(), clientport);
    //             break;
    //         }
    //     }
    // }

    ~tcp_server()
    {
    }

private:
    int _listensockfd;
    string _ip;     // IP地址
    uint16_t _port; // 端口
};